import os, sys
import jsonpickle

from osc_base import OSCBaseObject
from DeviceSystem.DeviceSystem import DeviceSystem
from DeviceSystem import Groups
from modifiers.EffectsSystem import EffectsSystem
from modifiers.snapshot import Stack, Snapshot



class MainController(OSCBaseObject):
    _saved_class_name = 'MainController'
    _saved_child_objects = ['Groups', 'CueStacks', 'Submasters']
    #saved_child_classes = ['Stack']
    def __init__(self, **kwargs):
        self.comm = kwargs.get('comm')
        self.osc_address = 'Main'
        self.osc_parent_node = self.comm.osc_io.root_node
        super(MainController, self).__init__(**kwargs)
        self.register_signal('child_added')
        ds_kwargs = {'comm':self.comm}
        ds_kwargs.update(self.add_osc_child(address='Devices'))
        self.DeviceSystem = DeviceSystem(**ds_kwargs)
        self.DeviceSystem.connect('new_device', self.on_ds_new_device)
        self.EffectsSystem = EffectsSystem(DeviceSystem=self.DeviceSystem)
        
        self.CueStacks = {}
        self.Submasters = {}
        #self.Selection = Groups.DeviceGroup.DeviceGroup(id='MainController_selection')
        #self.AllDevices = Groups.DeviceGroup.DeviceGroup(id='MainController_all_devices')
        self.Groups = {}
        self.load_globals()
        if len(self.Groups) == 0:
            for key in ['AllDevices', 'Selection']:
                g = Groups.DeviceGroup.DeviceGroup(id='MainController_%s' % (key))
                self.Groups.update({key:g})
        for key, val in self.Groups.iteritems():
            setattr(self, key, val)
        
    def add_to_selection(self, *args):
        self.Selection.add_devices(args)
        
    def remove_from_selection(self, *args):
        for arg in args:
            self.Selection.del_member(arg.id)
        
    def add_CueStack(self, **kwargs):
        '''
        :Parameters:
            id :
            name :
        '''
        kwargs.update({'MainController':self})
        stack = Stack(**kwargs)
        self.CueStacks.update({stack.id:stack})
        self.emit('child_added')
        return stack
        
    def store_to_CueStack(self, **kwargs):
        '''
        :Parameters:
            stack : stack object
            stack_id : stack object id
            cue_index : int, cue number, defaults to stack's current cue
            source : str or list, what to store ('all', 'selected', [list, of, objects])
        '''
        stack = kwargs.get('stack')
        stack_id = kwargs.get('stack_id')
        if not stack and stack_id is not None:
            stack = self.CueStacks[stack_id]
        index = kwargs.get('index', stack.current_index)
        source = kwargs.get('source', 'selected')
        if index:
            if type(source) == list or type(source) == tuple:
                obj_list = source
            elif source == 'selected':
                obj_list = [self.Selection]
            elif source == 'all':
                obj_list = [self.AllDevices]
            else:
                obj_list = []
            objects = dict(zip([obj.id for obj in obj_list], obj_list))
            stack.store_snapshot(index=index, objects=objects)
            return True
        return False
    
    def on_ds_new_device(self, **kwargs):
        id = kwargs.get('id')
        if kwargs.get('base') == 'PatchedDevice':
            obj = self.DeviceSystem.PatchedDevices[id]
            self.AllDevices.add_devices(obj)
            print 'mc AllDevices:', self.AllDevices.members
            
    def load_file(self, **kwargs):
        filename = kwargs.get('filename')
        string = kwargs.get('string', '')
        if filename is not None and os.path.exists(filename):
            file = open(filename, 'r')
            for line in file:
                string += line
            file.close()
        if string != '':
            d = jsonpickle.decode(string)
            for key in ['DeviceSystem', 'EffectsSystem']:
                if key in d:
                    getattr(self, key).from_json(string=jsonpickle.encode(d[key]))
            self.from_json(string)
        self.emit('child_added')
                    
    def save_file(self, **kwargs):
        filename = kwargs.get('filename')
        if filename:
            d = {}
            for key in ['DeviceSystem', 'EffectsSystem']:
                d.update({key:getattr(self, key)._get_saved_attr()})
            file = open(filename, 'w')
            file.write(self.to_json(d, indent=1))
            file.close()
            self.save_globals()
    
    def load_globals(self, **kwargs):
        kwargs.setdefault('filename', 'Globals.json')
        filename = kwargs.get('filename')
        string = kwargs.get('string', '')
        if filename is not None and os.path.exists(filename):
            file = open(filename, 'r')
            for line in file:
                string += line
            file.close()
        if string != '':
            d = jsonpickle.decode(string)
            for key in ['DeviceSystem', 'EffectsSystem']:
                if key in d:
                    getattr(self, key).load_globals(string=jsonpickle.encode(d[key]))
            self._load_saved_attr(d, saved_child_objects=['Groups'])
        
    def save_globals(self, **kwargs):
        filename = kwargs.get('filename', 'Globals.json')
        d = {}
        for key in ['DeviceSystem', 'EffectsSystem']:
            d.update({key:getattr(self, key).save_globals()})
        file = open(filename, 'w')
        file.write(self.to_json(d, saved_child_objects=['Groups']))
        file.close()
    
    def _deserialize_child(self, d):
        if d['saved_class_name'] == 'DeviceGroup':
            return Groups.DeviceGroup.DeviceGroup(deserialize=d)
        elif d['saved_class_name'] == 'Stack':
            return Stack(MainController=self, deserialize=d)
            
